package com.young.util;

import java.util.AbstractMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.ListIterator;
import java.util.Map;
import java.util.Set;

public class SimpleHashMap<K, V> extends AbstractMap<K, V> {

	static final int SIZE = 997;
	@SuppressWarnings("unchecked")
	LinkedList<MapEntry<K, V>>[] buckets = new LinkedList[SIZE];

	@Override
	public V put(K key, V value) {
		V oldValue = null;

		int index = Math.abs(key.hashCode()) % SIZE;
		if (buckets[index] == null)
			buckets[index] = new LinkedList<MapEntry<K, V>>();
		LinkedList<MapEntry<K, V>> bucket = buckets[index];
		MapEntry<K, V> pair = new MapEntry<K, V>(key, oldValue);
		boolean found = false;
		ListIterator<MapEntry<K, V>> it = bucket.listIterator();
		while (it.hasNext()) {
			MapEntry<K, V> iPair = it.next();
			if (iPair.getKey().equals(key)) {
				oldValue = iPair.getValue();
				it.set(iPair);
				found = true;
				break;
			}
		}
		if (!found) {
			buckets[index].add(pair);
		}

		return oldValue;
	}

	@Override
	public V get(Object key) {
		int index = Math.abs(key.hashCode()) % SIZE;
		if (buckets[index] == null) return null;
		for(MapEntry<K, V> iPair : buckets[index]) {
			if(iPair.getKey().equals(key)){
				return iPair.getValue();
			}
		}
		return null;
	}

	@Override
	public Set<java.util.Map.Entry<K, V>> entrySet() {
		Set<Map.Entry<K, V>> set = new HashSet<Map.Entry<K,V>>();
		for(LinkedList<MapEntry<K, V>> bucket : buckets ) {
			if(bucket == null) continue;
			for(MapEntry<K, V> mpair : bucket) {
				set.add(mpair);
			}
		}
		return set;
	}

	static class MapEntry<K, V> implements Map.Entry<K, V> {

		private K key;
		private V value;

		MapEntry(K key, V value) {
			this.key = key;
			this.value = value;
		}

		@Override
		public K getKey() {
			return key;
		}

		@Override
		public V getValue() {
			return value;
		}

		@Override
		public V setValue(V value) {
			V result = this.value;
			this.value = value;
			return result;
		}

		@Override
		public int hashCode() {
			return (key == null ? 0 : key.hashCode())
					^ (value == null ? 0 : value.hashCode());
		}

		@Override
		public boolean equals(Object o) {
			if (!(o instanceof MapEntry))
				return false;
			MapEntry me = (MapEntry) o;
			return (key == null ? me.getKey() == null : key.equals(me.getKey())
					&& value == null ? me.getValue() == null : value.equals(me
					.getValue()));
		}

		public String toString() {
			return key + "=" + value;
		}

	}

}
